#include "board.h"
#include "BoardViewer.h"
Board::Board()
{
    for(int r = 1; r != ROWS + 1; ++r)
        for(int c = 1; c != COLS + 1; ++c){
            b_[r][c] = Empty;
        }
    for(int col = 0; col <= COLS + 1; ++col){
        b_[0][col] = Fense;
        b_[ROWS+1][col] = Fense;
    }
    for(int row = 0; row <= ROWS + 1; ++row){
        b_[row][0] = Fense;
        b_[row][COLS+1] = Fense;
    }
    b_[ROWS/2][COLS/2] = b_[ROWS/2 + 1][COLS/2 + 1] = White;
    b_[ROWS/2 + 1][COLS/2] = b_[ROWS/2][COLS/2 +1] = Black;
    black_score_ = white_score_ = 2;
}
void Board::add_viewer(BoardViewer* bv)
{
    viewers_.push_back(bv);
}
int Board::score(Color color)const{
    return color == White? white_score_ : black_score_;
}
MoveResult Board::valid_move(Color color, int r, int c)const
{
    if(b_[r][c] != Empty){
        return Unsuccessful;
    }
    Color opponent = opponent_of(color);
    for(int dr = -1; dr != 2; ++dr){
        for(int dc = -1; dc != 2; ++dc){
            if((dr != 0) || (dc != 0)){
                int row = r, col =c;
                do{
                    row += dr;
                    col += dc;
                }while(b_[row][col] == opponent);
                if((b_[row][col] == color) && ((row != r+dr || col != c+dc))){
                    return Successful;
                }
            }
        }
    }
    return Unsuccessful;
}
void Board::update_viewers(int row, int col, Color color)
{
    typedef std::vector<BoardViewer*>::iterator IT;
    IT end = viewers_.end();
    for(IT it = viewers_.begin(); it != end; ++it){
        (*it)->update(row, col, color);
    }
}

//Call valid_move first, then call me
void Board::move(Color color, int r, int c)
{
    update_viewers(r, c, color);
    Color opponent = opponent_of(color);
    int count = 0;
    for(int dr = -1; dr != 2; ++dr){
        for(int dc = -1; dc != 2; ++dc){
            if((dr != 0) || (dc != 0)){
                int row = r, col =c;
                do{
                    row += dr;
                    col += dc;
                }while(b_[row][col] == opponent);
                // change the color
                if((b_[row][col] == color) && ((row != r + dr || col != c + dc))){
                    for(row = r + dr, col = c + dc; b_[row][col] == opponent;
                        row += dr, col += dc){
                        b_[row][col] = color;
                        update_viewers(row, col, color);
                        ++count;
                    }

                }
            }
        }
    }
    b_[r][c] = color;
    if(color == Black){
        black_score_ += count + 1;
        white_score_ += count;
    }
    else{
        white_score_ += count + 1;
        black_score_ -= count;
    }
}
MoveResult Board::get_possible_move(Color color, int& r, int& c)const
{
    for(r = 1; r != ROWS +1; ++r)
        for(c = 1; c != COLS+1; ++c){
            if(valid_move(color, r, c)){
                return Successful;
            }
        }
    return Unsuccessful;
}

Color opponent_of(Color color)
{
    assert(color != Empty);
    return color == Black? White:Black;
}
//used for debug
ostream& operator <<(ostream& os, const Board& board)
{
    for(int i = 0; i < Board::ROWS+2; i++){
        for(int j = 0; j < Board::COLS+2; j++){
            if(board.b_[i][j] == Empty){
                os << " ";
            }
            else if(board.b_[i][j] == Black){
                os << "*";
            }
            else if(board.b_[i][j] == White){
                os << "0";
            }
            else{
                os << "#";
            }
        }
        os << endl;
    }
    return os;
}



